/*
	This file is a part of Awesomium, a library that makes it easy for 
	developers to embed web-content in their applications.

	Copyright (C) 2009 Adam J. Simmons

	Project Website:
	<http://princeofcode.com/awesomium.php>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
	02110-1301 USA
*/

#ifndef __WEBVIEWPROXY_H__
#define __WEBVIEWPROXY_H__

#include "WebView/RenderBuffer.h"
#include "WebView/PopupWidget.h"
#include "API/WebView.h"
#include "javascript/ClientObject.h"

#include <vector>
#include "base/basictypes.h"
#include "third_party/WebKit/WebKit/chromium/public/webview.h"
#include "third_party/WebKit/WebKit/chromium/public/webframe.h"
#include "WebCursorInfo.h"
#include "WebURLRequest.h"
#include "WebNavigationType.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/webdropdata.h"
#include "webkit/glue/webcursor.h"
#include "platform_canvas.h"
#include "WebHTTPBody.h"
#include "WebInputEvent.h"
#include "WebHistoryItem.h"
#include "SkCanvas.h"
#include "base/gfx/rect.h"
#include "base/message_loop.h"
#include "base/timer.h"
#include "base/lock.h"
#include "base/waitable_event.h"

#include "third_party/WebKit/WebKit/chromium/public/WebViewClient.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h"
#include "third_party/WebKit/WebKit/chromium/public/WebPageSerializerClient.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/webplugin_page_delegate.h"
#include "chrome/common/navigation_gesture.h"

using WebKit::WebFrame;
class NavigationEntry;
class NavigationController;

using namespace WebKit;

class WebViewProxy : public WebKit::WebViewClient,
                     public WebKit::WebFrameClient,
                     public webkit_glue::WebPluginPageDelegate,
									   public base::SupportsWeakPtr<WebViewProxy>,
                     public base::RefCountedThreadSafe<WebViewProxy>
{
	int width, height;
	gfx::Rect dirtyArea;
  gfx::Rect asyncUpdatedArea;
	Awesomium::RenderBuffer* renderBuffer;
	Awesomium::RenderBuffer* asyncRenderBuffer;
	skia::PlatformCanvas* canvas;
	int mouseX, mouseY;
	int buttonState;
	int modifiers;
	::WebView* view;
	Awesomium::WebView* parent;
	std::vector<PopupWidget*> popups;
	bool isPopupsDirty;
	ClientObject* clientObject;
	WebCursor curCursor;
	WebString curTooltip;
	Lock asyncRenderBufferLock;
	base::RepeatingTimer<WebViewProxy> asyncRenderTimer;
	const bool enableAsyncRendering;
	bool isAsyncRenderDirty;
	int maxAsyncRenderPerSec;
	Awesomium::WebView::TransparencyMode transparencyMode;
	GURL lastTargetURL;
	NavigationController* navController;
	int pageID, nextPageID;

  // For tracking session history.  See RenderView.
  int page_id_;
  int last_page_id_updated_;
  // Edit command associated to the current keyboard event.
  std::string edit_command_name_;
  std::string edit_command_value_;

	friend class NavigationController;

	void closeAllPopups();
	void handleMouseEvent(WebKit::WebInputEvent::Type type, short buttonID);
	void overrideIFrameWindow(const std::wstring& frameName);
	bool navigate(NavigationEntry& entry, bool reload);

		void updateForCommittedLoad(WebFrame* frame, bool is_new_navigation);
		void updateURL(WebFrame* frame);
		void updateSessionHistory(WebFrame* frame);
	
		template <class EventType> void initializeWebEvent(EventType &event, WebKit::WebInputEvent::Type type);

	WebKit::WebRect paintRenderBuffer();

  void paintAsyncRenderBuffer();

  void layoutPaintCanvas(const gfx::Rect& invalidArea);
  void copyCanvasToRenderBuffer(const gfx::Rect& invalidArea);

  void paintEstimateAlpha(const gfx::Rect& invalidArea);

  friend class base::RefCountedThreadSafe<WebViewProxy>;
  virtual ~WebViewProxy();

public:

	WebViewProxy(int width, int height, bool enableAsyncRendering, int maxAsyncRenderPerSec, Awesomium::WebView* parent);

	void asyncStartup();
	void asyncShutdown();

	std::string GetResourceDescription(uint32 identifier);

  void loadURL(const std::string& url, const std::wstring& frameName);
	void loadHTML(const std::string& html, const std::wstring& frameName);
	void loadFile(const std::string& file, const std::wstring& frameName);

	void goToHistoryOffset(int offset);
	void refresh();

	void executeJavascript(const std::string& javascript, const std::wstring& frameName = std::wstring());
  void executeJavascriptWithSignal(const std::string& javascript, const std::wstring& frameName, base::WaitableEvent* doneEvent);

	void setProperty(const std::string& name, const Awesomium::JSValue& value);
	void setCallback(const std::string& name);

  void getNPObjectProperty(NPObject* object, NPIdentifier propertyName, NPVariant* result, base::WaitableEvent* doneEvent);
  void invokeNPObject(NPObject* object, NPIdentifier methodName, const NPVariant* args, uint32_t count, NPVariant* result, base::WaitableEvent* doneEvent);
  void invokeNPObjectDefault(NPObject* object, const NPVariant* args, uint32_t count, NPVariant* result, base::WaitableEvent* doneEvent);
  
  void copyAsyncRenderBuffer(unsigned char* destination, int destRowSpan, Awesomium::WebView::RenderCopyMode copyMode, Awesomium::Rect* renderedRect);

	void renderSync(unsigned char* destination, int destRowSpan, Awesomium::WebView::RenderCopyMode copyMode, Awesomium::Rect* renderedRect);

  void syncLayout(base::WaitableEvent* event_);

	void injectMouseMove(int x, int y);
	void injectMouseDown(short mouseButtonID);
	void injectMouseUp(short mouseButtonID);
	void injectMouseWheel(int scrollAmountX, int scrollAmountY);

	void injectKeyEvent(bool press, int modifiers, int windowsCode, int nativeCode);
	void injectTextEvent(string16 text);
#if defined(_WIN32)
	void injectKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
#elif defined(__APPLE__)
	void injectKeyboardEvent(NSEvent* keyboardEvent);
#endif

	void cut();
	void copy();
	void paste();

	void selectAll();
	void deselectAll();

	void getContentAsText(std::wstring* result, int maxChars);

	void zoomIn();
	void zoomOut();
	void resetZoom();

	void resize(int width, int height);

  void setTransparencyMode(Awesomium::WebView::TransparencyMode mode);
  void getTransparencyMode(Awesomium::WebView::TransparencyMode* result);

	void invalidatePopups();

	void closePopup(PopupWidget* popup);

	void checkKeyboardFocus();

	WebView* createView(WebFrame* creator);

  WebWidget* createPopupMenu(bool activatable);
  WebWidget* createPopupMenu(const WebPopupMenuInfo&);

	/**
	* The following functions are inherited from  WebViewClient ------------------------------------------------------------------------------------------
	*/

		void runModalAlertDialog(     WebFrame*, const WebString& message);
		bool runModalConfirmDialog(  WebFrame*, const WebString& message);
		bool runModalPromptDialog( WebFrame*, const WebString& message, const WebString& defaultValue,  WebString* actualValue);

		bool runModalBeforeUnloadDialog(WebFrame*, const WebString& message);

		//mgdesign, chrome v5: 
		//bool runFileChooser(const WebFileChooserParams&,WebFileChooserCompletion*);
		//mgdesign, chrome v4: 
    bool runFileChooser(  bool multiSelect, const WebString& title, const WebString& initialValue, WebFileChooserCompletion*);

		void showContextMenu(WebFrame*, const WebContextMenuData&);

		void startDragging(	const WebPoint& from, const WebDragData&, WebDragOperationsMask);
	
		WebKit::WebMediaPlayer* createWebMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client);

    void didStartLoading();
    void didStopLoading();

		void didAddMessageToConsole( const WebKit::WebConsoleMessage& message,  const WebKit::WebString& source_name, unsigned source_line);

		void didFinishResourceLoad( WebFrame* frame, unsigned identifier);
    void didFailResourceLoad( WebFrame*, unsigned identifier, const WebURLError&);

    void focusNext();
    void focusPrevious();

    bool shouldBeginEditing(const WebRange&);
		bool shouldEndEditing(const WebRange&);
		bool shouldInsertNode(const WebNode&, const WebRange&, WebEditingAction);
		bool shouldInsertText(const WebString&, const WebRange&, WebEditingAction);
		bool shouldChangeSelectedRange(const WebRange& from, const WebRange& to, WebTextAffinity,bool stillSelecting);
		bool shouldDeleteRange(const WebRange&) ;
		bool shouldApplyStyle(const WebString& style, const WebRange&) ;

		bool isSmartInsertDeleteEnabled();

		void didBeginEditing();
    void didChangeSelection(bool isSelectionEmpty);
    void didChangeContents();
    void didExecuteCommand(const WebString& commandName);
    void didEndEditing();

		void navigateBackForwardSoon(int offset);

		int historyBackListCount();
		int historyForwardListCount();

    void setToolTipText(const WebString&, WebTextDirection hint);

		void spellCheck( const WebString& text, int& misspelledOffset, int& misspelledLength);

		void setInputMethodEnabled(bool enabled);

		void printPage(WebFrame*);

	//mgdesign: developper tools
	//void WebInspectorOpened(int num_resources);

	/**
	* The following functions are inherited from  WebFrameClient ------------------------------------------------------------------------------------------
	*/

		WebKit::WebPlugin* createPlugin( WebKit::WebFrame*, const WebKit::WebPluginParams&);
		bool allowPlugins(WebFrame* frame, bool enabled_per_settings);

		void didReceiveTitle(WebFrame* frame, const std::wstring& title);

		void didCreateScriptContext();
		void didClearWindowObject(WebFrame* frame);

		void willPerformClientRedirect( WebFrame*, const WebURL& from, const WebURL& to,   double interval, double fireTime);

		void didReceiveResponse( WebFrame* frame, unsigned identifier, const WebURLResponse& response);

		void didCancelClientRedirect(WebFrame*);

		//mgdesign, add from test_webview_delegate.cc :
		bool canHandleRequest(WebFrame* frame, const WebURLRequest& request);
		WebURLError cannotHandleRequestError(WebFrame* frame, const WebURLRequest& request);
		WebURLError cancelledError(WebFrame*, const WebURLRequest& request);
		void unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error);

		void didCompleteClientRedirect(WebFrame*, const WebURL& fromURL);

		void willClose(WebFrame*);

		void assignIdentifierToRequest( WebFrame*, unsigned identifier, const WebURLRequest&);

		void willSendRequest( WebFrame*, unsigned identifier, WebURLRequest&, const WebURLResponse& redirectResponse);

		void didReceiveDocumentData(  WebFrame*, const char* data, size_t length, bool& preventDefault);

		void didUpdateCurrentHistoryItem(WebFrame*);

		void didExhaustMemoryAvailableForScript(WebFrame*);

		void didChangeLocationWithinPage(WebFrame*, bool isNewNavigation);

		void didHandleOnloadEvents(WebFrame*);

		void didLoadResourceFromMemoryCache(WebFrame*, const WebURLRequest&, const WebURLResponse&);

		void didCommitProvisionalLoad(WebFrame*, bool isNewNavigation);

		void didFinishLoad(WebFrame*);

		void didFailLoad(WebFrame*, const WebURLError&);

		void didFinishDocumentLoad(WebFrame*);

    void didStartProvisionalLoad(WebFrame*);
    void didReceiveServerRedirectForProvisionalLoad(WebFrame*);
    void didFailProvisionalLoad(WebFrame*, const WebURLError&);

		WebKit::WebNavigationPolicy decidePolicyForNavigation(WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationType,const WebKit::WebNode& originatingNode,WebKit::WebNavigationPolicy defaultPolicy, bool isRedirect);

		void loadURLExternally( WebFrame*, const WebURLRequest&, WebNavigationPolicy);

	/**
	* The following functions are inherited from  WebPluginPageDelegate ------------------------------------------------------------------------------------------
	*/

		void ShowModalHTMLDialog(const GURL& url, int width, int height, const std::string& json_arguments, std::string* json_retval);
	
		webkit_glue::WebPluginDelegate* CreatePluginDelegate(const GURL& url, const std::string& mime_type, std::string* actual_mime_type);

		// Called when a windowed plugin is created.
		// Lets the view delegate create anything it is using to wrap the plugin.
		void CreatedPluginWindow(  gfx::PluginWindowHandle handle);

		// Called when a windowed plugin is closing.
		// Lets the view delegate shut down anything it is using to wrap the plugin.
		void WillDestroyPluginWindow( gfx::PluginWindowHandle handle);

		// Keeps track of the necessary window move for a plugin window that resulted
		// from a scroll operation.  That way, all plugin windows can be moved at the
		// same time as each other and the page.
		///void DidMovePlugin(const WebPluginGeometry& move);
		void DidMovePlugin(const webkit_glue::WebPluginGeometry& move);

		// Notifies the parent view that a load has begun.
		void DidStartLoadingForPlugin();

		// Notifies the parent view that all loads are finished.
		void DidStopLoadingForPlugin();

		// Asks the browser to show a modal HTML dialog.  The dialog is passed the
		// given arguments as a JSON string, and returns its result as a JSON string
		// through json_retval.
		void ShowModalHTMLDialogForPlugin( const GURL& url,  const gfx::Size& size,  const std::string& json_arguments,  std::string* json_retval);

	// added by mgdesign, for chrome v4, remove in v5 ?
		WebKit::WebCookieJar* GetCookieJar();

	/**
	* The following functions are inherited from  WebWidgetClient ------------------------------------------------------------------------------------------
	*/
	
		void didInvalidateRect(const WebKit::WebRect& rect);

		void didScrollRect(int dx, int dy, const WebKit::WebRect& clip_rect);

		void closeWidgetSoon();

		void didFocus();

		void didBlur();

		void didChangeCursor(const WebKit::WebCursorInfo& cursor);

		WebKit::WebRect windowRect();

		void setWindowRect(const WebKit::WebRect& rect);

		WebKit::WebRect rootWindowRect();

		WebKit::WebRect windowResizerRect();

		void runModal();

		void show(WebKit::WebNavigationPolicy);

		WebKit::WebScreenInfo screenInfo();

		DISALLOW_COPY_AND_ASSIGN(WebViewProxy);
};

#endif
